﻿using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections;
using System.ComponentModel;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;

namespace TA.Turbo.Controls
{
	/// <summary>
	/// Summary description for Template
	/// </summary>
	public abstract class MarkupTemplate : IAttributeAdder
	{
		protected MarkupTemplate(Control owner, string name, TemplateInstance instance)
		{

			_instance = instance;
			_name = name;
			_owner = owner;
			_owner.Init += new EventHandler(owner_Init);
		}

		#region PUBLIC
		#region PROPS
		public string Markup
		{
			get
			{
				PrepareMarkupAndScript();
				return _markup;
			}
		}
		public string Script
		{
			get
			{
				PrepareMarkupAndScript();
				return _script;
			}
		}
		#endregion
		#region METHODS
		public void AddAttributes(HtmlTextWriter writer)
		{
			writer.AddAttribute(_name + "_Markup", Markup);
			writer.AddAttribute(_name + "_Script", Script);
		}
		#endregion
		#endregion
		#region INTERNAL
		#region VARS
		static Regex rgxGetScript = new Regex(@"<script([^>]*>)(?<Script>(.|\s)+?)</script>");
		protected ITemplate _template;
		string _name, _markup, _script;
		bool _done;
		TemplateInstance _instance;
		Control _owner;
		GenericTemplateContainer _container;
		#endregion
		#region METHODS
		void owner_Init(object sender, EventArgs e)
		{
			if (_template != null)
			{
				_container = new GenericTemplateContainer(this);
				_owner.Controls.Add(_container);
				_container.ID = _name;
				_template.InstantiateIn(_container);
			}
		}
		private void PrepareMarkupAndScript()
		{
			if (_done) return;


			string res = "";
			using (StringWriter sw = new StringWriter())
			{
				using (HtmlTextWriter tw = new HtmlTextWriter(sw))
				{
					_container.RenderControl(tw);
					res = sw.ToString();
				}
			}

			MatchCollection mclScripts = rgxGetScript.Matches(res);
			StringBuilder sbScript = new StringBuilder();
			foreach (Match m in mclScripts)
				sbScript.AppendLine(m.Groups["Script"].Value);

			_script = sbScript.ToString();
			_markup = rgxGetScript.Replace(res, "");

			_done = true;
		}
		#endregion
		#endregion
		protected class GenericTemplateContainer : Control, INamingContainer
		{
			internal GenericTemplateContainer(MarkupTemplate owner)
			{
				_owner = owner;
			}
			public override void RenderControl(HtmlTextWriter writer)
			{
				if (_owner._instance == TemplateInstance.Single)
					base.RenderControl(writer);
				else if (writer.InnerWriter is StringWriter)
				{
					bool isTableRow = Controls.Count > 0
						&&
						Controls[0] is LiteralControl
						&&
						rgxIsTableRow.IsMatch(((LiteralControl)Controls[0]).Text);

					if (isTableRow)
					{
						writer.RenderBeginTag(HtmlTextWriterTag.Table);
						writer.RenderBeginTag(HtmlTextWriterTag.Tbody);
					}

					base.RenderControl(writer);

					if (isTableRow)
					{
						writer.RenderEndTag();
						writer.RenderEndTag();
					}
				}
			}

			static Regex rgxIsTableRow = new Regex("[^<]*<tr");
			MarkupTemplate _owner;
		}

	}
	public class SingleInstanceTemplate : MarkupTemplate
	{
		public SingleInstanceTemplate(Control owner, string name)
			: base(owner, name, TemplateInstance.Single)
		{
		}
		[PersistenceMode(PersistenceMode.InnerProperty),
		TemplateContainer(typeof(GenericTemplateContainer)),
		MergableProperty(false),
		Browsable(false),
		TemplateInstance(TemplateInstance.Single)]
		public ITemplate Template { get { return _template; } set { _template = value; } }
	}
	public class MultipleInstanceTemplate : MarkupTemplate
	{
		public MultipleInstanceTemplate(Control owner, string name)
			: base(owner, name, TemplateInstance.Multiple)
		{
		}
		[PersistenceMode(PersistenceMode.InnerProperty),
		TemplateContainer(typeof(GenericTemplateContainer)),
		MergableProperty(false),
		Browsable(false),
		TemplateInstance(TemplateInstance.Multiple)]
		public ITemplate Template { get { return _template; } set { _template = value; } }
	}
}